{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "69cb775b-eb44-4e95-83c2-c087947d7ae4",
   "metadata": {},
   "source": [
    "# LangChain 核心模块 - Chat Model 和 Chat Prompt Template\n",
    "\n",
    "希望通过此示例，让大家深入理解 LangChain 的聊天模型。简而言之：\n",
    "- `Chat Model` 不止是一个用于聊天对话的模型抽象，更重要的是提供了`多角色`提示能力（System,AI,Human,Function)。\n",
    "- `Chat Prompt Template` 则为开发者提供了便捷维护`不同角色`的`提示模板`与`消息记录`的接口。\n",
    "\n",
    "![](../../jupyter/images/model_io.jpeg)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2219b200-bb76-45b7-bb88-0525667c1b31",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "8a376a3d-ce1f-4aab-9a2a-6224fce2edfd",
   "metadata": {},
   "source": [
    "## 温故：LangChain Chat Model 使用方法和流程\n",
    "\n",
    "在最终调用 `Chat Model` 时，一定是直接传入`LangChain Schema Messages（消息记录）` \n",
    "\n",
    "```python\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "chat_model = ChatOpenAI(model_name=\"gpt-3.5-turbo\")\n",
    "\n",
    "from langchain.schema import (\n",
    "    AIMessage,\n",
    "    HumanMessage,\n",
    "    SystemMessage\n",
    ")\n",
    "\n",
    "messages = [SystemMessage(content=\"You are a helpful assistant.\"),\n",
    " HumanMessage(content=\"Who won the world series in 2020?\"),\n",
    " AIMessage(content=\"The Los Angeles Dodgers won the World Series in 2020.\"), \n",
    " HumanMessage(content=\"Where was it played?\")]\n",
    "\n",
    "print(messages)\n",
    "\n",
    "chat_model(messages)\n",
    "```\n",
    "\n",
    "打印 messages 输出结果：\n",
    "```\n",
    "[\n",
    "    SystemMessage(content=\"You are a helpful assistant.\", additional_kwargs={}),\n",
    "    HumanMessage(\n",
    "        content=\"Who won the world series in 2020?\", additional_kwargs={}, example=False\n",
    "    ),\n",
    "    AIMessage(\n",
    "        content=\"The Los Angeles Dodgers won the World Series in 2020.\",\n",
    "        additional_kwargs={},\n",
    "        example=False,\n",
    "    ),\n",
    "    HumanMessage(content=\"Where was it played?\", additional_kwargs={}, example=False),\n",
    "]\n",
    "```\n",
    "\n",
    "调用 chat_model(messages) 返回结果：\n",
    "\n",
    "```\n",
    "AIMessage(\n",
    "    content=\"The 2020 World Series was played at Globe Life Field in Arlington, Texas.\",\n",
    "    additional_kwargs={},\n",
    "    example=False,\n",
    ")\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44337cac-457c-4971-b382-498dec3e3c24",
   "metadata": {},
   "source": [
    "## 使用 System 和 Human 角色的提示模板构造 ChatPromptTemplate\n",
    "\n",
    "使用 `ChatPromptTemplate.from_messages` 方法，类似使用和维护`messages`的方式，构造 `chat_prompt_template`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "0e4d76a2-1ccb-421a-9be2-1a4a6faa3b8b",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.schema import AIMessage, HumanMessage, SystemMessage\n",
    "# 导入 Chat Model 即将使用的 Prompt Templates\n",
    "from langchain.prompts.chat import (\n",
    "    ChatPromptTemplate,\n",
    "    SystemMessagePromptTemplate,\n",
    "    AIMessagePromptTemplate,\n",
    "    HumanMessagePromptTemplate,\n",
    ")\n",
    "\n",
    "# 翻译任务指令始终由 System 角色承担\n",
    "template = (\n",
    "    \"\"\"You are a translation expert, proficient in various languages. \\n\n",
    "    Translates English to Chinese.\"\"\"\n",
    ")\n",
    "system_message_prompt = SystemMessagePromptTemplate.from_template(template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "596d74c4-0fa5-4308-9920-c8002a3ee0c7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "prompt=PromptTemplate(input_variables=[], output_parser=None, partial_variables={}, template='You are a translation expert, proficient in various languages. \\n\\n    Translates English to Chinese.', template_format='f-string', validate_template=True) additional_kwargs={}\n"
     ]
    }
   ],
   "source": [
    "print(system_message_prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "d2a8fddd-31d7-493f-94a1-4c1ec4608de6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 待翻译文本由 Human 角色输入\n",
    "human_template = \"{text}\"\n",
    "human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "8922d062-00a9-48dd-b1e2-ed2d2f61a9ad",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "prompt=PromptTemplate(input_variables=['text'], output_parser=None, partial_variables={}, template='{text}', template_format='f-string', validate_template=True) additional_kwargs={}\n"
     ]
    }
   ],
   "source": [
    "print(human_message_prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "125cef74-88a0-4775-a513-06692592d801",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用 System 和 Human 角色的提示模板构造 ChatPromptTemplate\n",
    "chat_prompt_template = ChatPromptTemplate.from_messages(\n",
    "    [system_message_prompt, human_message_prompt]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "d16f01ad-b7c9-4a0a-af8f-698f55d4762e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "input_variables=['text'] output_parser=None partial_variables={} messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], output_parser=None, partial_variables={}, template='You are a translation expert, proficient in various languages. \\n\\n    Translates English to Chinese.', template_format='f-string', validate_template=True), additional_kwargs={}), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['text'], output_parser=None, partial_variables={}, template='{text}', template_format='f-string', validate_template=True), additional_kwargs={})]\n"
     ]
    }
   ],
   "source": [
    "print(chat_prompt_template)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "406a2804-96f5-4470-9464-a96572e31149",
   "metadata": {},
   "source": [
    "### 规范化 Python 复杂对象\n",
    "\n",
    "- 使用在线工具 [Python Formatter](https://codebeautify.org/python-formatter-beautifier) \n",
    "- 规范化 `chat_prompt_template`后再查看\n",
    "- 注意：不要同事输入多个复杂对象\n",
    "\n",
    "```json\n",
    "messages = [\n",
    "    SystemMessagePromptTemplate(\n",
    "        prompt=PromptTemplate(\n",
    "            input_variables=[],\n",
    "            output_parser=None,\n",
    "            partial_variables={},\n",
    "            template=\"You are a translation expert, proficient in various languages. \\n\\n    Translates English to Chinese.\",\n",
    "            template_format=\"f-string\",\n",
    "            validate_template=True,\n",
    "        ),\n",
    "        additional_kwargs={},\n",
    "    ),\n",
    "    HumanMessagePromptTemplate(\n",
    "        prompt=PromptTemplate(\n",
    "            input_variables=[\"text\"],\n",
    "            output_parser=None,\n",
    "            partial_variables={},\n",
    "            template=\"{text}\",\n",
    "            template_format=\"f-string\",\n",
    "            validate_template=True,\n",
    "        ),\n",
    "        additional_kwargs={},\n",
    "    ),\n",
    "]\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "b5cf9238-9497-46c3-961f-860e797fcece",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptValue(messages=[SystemMessage(content='You are a translation expert, proficient in various languages. \\n\\n    Translates English to Chinese.', additional_kwargs={}), HumanMessage(content='I love programming.', additional_kwargs={}, example=False)])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 生成用于翻译的 Chat Prompt\n",
    "chat_prompt_template.format_prompt(text=\"I love programming.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d3a39ff5-2720-40db-80f4-913c8c622bfa",
   "metadata": {},
   "source": [
    "## 使用 chat_prompt_template.to_messages 方法生成 Messages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "a21508c5-4b13-4d0e-aa67-c56d554d2626",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成聊天模型真正可用的消息记录 Messages\n",
    "chat_prompt = chat_prompt_template.format_prompt(text=\"I love programming.\").to_messages()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a158a289-e738-45e8-b440-3f857a708e57",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[SystemMessage(content='You are a translation expert, proficient in various languages. \\n\\n    Translates English to Chinese.', additional_kwargs={}),\n",
       " HumanMessage(content='I love programming.', additional_kwargs={}, example=False)]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat_prompt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "56e2fa43-ba3c-401f-bba0-6bb27050a363",
   "metadata": {},
   "source": [
    "## 使用 Chat Model（GPT-3.5-turbo）实际执行翻译任务\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "5d4e3bd9-fac3-4b67-9285-74e1793f9e74",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chat_models import ChatOpenAI\n",
    "\n",
    "# 为了翻译结果的稳定性，将 temperature 设置为 0\n",
    "translation_model = ChatOpenAI(model_name=\"gpt-3.5-turbo\", temperature=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "c46d710c-9892-4ce2-8dcf-c3450dae8d83",
   "metadata": {},
   "outputs": [],
   "source": [
    "translation_result = translation_model(chat_prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "63d7cadf-515a-41cd-82d7-1498a3d6a35f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='我喜欢编程。', additional_kwargs={}, example=False)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "translation_result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "d56c7a65-bc6c-4e19-8176-ddc457696d0b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我喜欢编程。\n"
     ]
    }
   ],
   "source": [
    "# 查看翻译结果\n",
    "print(translation_result.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "75f3e72a-90e0-40dc-afa8-0ff96c2b7d72",
   "metadata": {},
   "source": [
    "## 使用 LLMChain 简化重复构造 ChatPrompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "4a57ee8c-dad1-429c-a791-2797a7b0c4ef",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import LLMChain\n",
    "\n",
    "# 无需再每次都使用 to_messages 方法构造 Chat Prompt\n",
    "translation_chain = LLMChain(llm=translation_model, prompt=chat_prompt_template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "723cebfa-a3bd-434f-9992-9ec25833acdf",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 等价于 translation_result.content (字符串类型)\n",
    "chain_result = translation_chain.run({'text': \"I love programming.\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "21e1d186-88de-4ca8-ad32-c233d99145c4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我喜欢编程。\n"
     ]
    }
   ],
   "source": [
    "print(chain_result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "faddd232-0308-45ce-b2a6-899f261abe57",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'我喜欢人工智能和大型语言模型。'"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "translation_chain.run({'text': \"I love AI and Large Language Model.\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "4f3dcb51-7e3f-4787-84aa-60f45def661e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'[水果, 颜色, 价格（美元）] [苹果, 红色, 1.20] [香蕉, 黄色, 0.50] [橙子, 橙色, 0.80] [草莓, 红色, 2.50] [蓝莓, 蓝色, 3.00] [猕猴桃, 绿色, 1.00] [芒果, 橙色, 1.50] [葡萄, 紫色, 2.00]'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "translation_chain.run({'text': \"[Fruit, Color, Price (USD)] [Apple, Red, 1.20] [Banana, Yellow, 0.50] [Orange, Orange, 0.80] [Strawberry, Red, 2.50] [Blueberry, Blue, 3.00] [Kiwi, Green, 1.00] [Mango, Orange, 1.50] [Grape, Purple, 2.00]\"})\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a47a1bfd-2beb-41eb-a1c1-c6443e4ec129",
   "metadata": {},
   "source": [
    "## 扩展：支持多语言对翻译"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "bb9b37f6-4bcb-450c-b3c6-e476a8f15bc7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# System 增加 source_language 和 target_language\n",
    "template = (\n",
    "    \"\"\"You are a translation expert, proficient in various languages. \\n\n",
    "    Translates {source_language} to {target_language}.\"\"\"\n",
    ")\n",
    "system_message_prompt = SystemMessagePromptTemplate.from_template(template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "2fccc32f-2b3f-4666-82be-607c452893b7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 待翻译文本由 Human 角色输入\n",
    "human_template = \"{text}\"\n",
    "human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "fd937e81-c54f-49d9-9422-c43670d8e5db",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用 System 和 Human 角色的提示模板构造 ChatPromptTemplate\n",
    "m_chat_prompt_template = ChatPromptTemplate.from_messages(\n",
    "    [system_message_prompt, human_message_prompt]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "ab237375-59ab-40ac-986b-7254989b3418",
   "metadata": {},
   "outputs": [],
   "source": [
    "m_translation_chain = LLMChain(llm=translation_model, prompt=m_chat_prompt_template) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "e728621c-008e-4c2b-bb57-483f1ee4c1e8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'I enjoy studying large language models, as it is easy, simple, and enjoyable.'"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m_translation_chain.run({\n",
    "    \"source_language\": \"Chinese\",\n",
    "    \"target_language\": \"English\",\n",
    "    \"text\": \"我喜欢学习大语言模型，轻松简单又愉快\",\n",
    "})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "183455b3-9cf1-42b4-be91-9c699248266a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'私は大規模言語モデルの学習が好きです。それは簡単で楽しいです。'"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m_translation_chain.run({\n",
    "    \"source_language\": \"Chinese\",\n",
    "    \"target_language\": \"Japanese\",\n",
    "    \"text\": \"我喜欢学习大语言模型，轻松简单又愉快\",\n",
    "})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d42bf232-d2ef-47d8-9029-97940d7f784a",
   "metadata": {},
   "source": [
    "## Homework\n",
    "- 尝试不同的 System Prompt 和 Chat Model，对比翻译效果。\n",
    "- 根据翻译任务的使用场景，是否可以在初次传入 source_language 和 target_language 后不再更新？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "38ee618a-bbaa-476f-80e6-8d22a81fddf6",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
